/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package datamodel;

import core.IMAPMIDlet;
import core.NotificationManager;
import core.Settings;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import javax.microedition.lcdui.Display;
import javax.microedition.media.Manager;
import javax.microedition.media.MediaException;
import javax.microedition.media.Player;
import javax.microedition.media.PlayerListener;
import javax.microedition.media.control.VolumeControl;
import utils.BacklightHelper;

/**
 *
 * @author Kvest
 */
public class Notification implements Runnable
{
    private static final int VIBRATION_LENGTH = 1000;
    private static final int BEEP_LENGTH = 1000;
    private static final int BEEP_NOTE = 60;
    
    private static final String SOUND_TYPE = "audio/midi";
    private static final String NEW_ORDER_MELODY = "/sound/new_order.mid";
    private static final String NEW_MESSAGE_MELODY = "/sound/message.mid";
    private static final String ORDER_STATE_CHANGED_MELODY = "/sound/change_state.mid";
    private static final String ORDER_CANCELED_MELODY = "/sound/cancel_order.mid";
    private static final String CONNECTION_ERROR_MELODY = "/sound/connect_error.mid";
    private static final String NEW_EFIR_ORDER_MELODY = "/sound/efir_order.mid";
    private static final String FIRST_IN_QUEUE_MELODY = "/sound/first_in_queue.mid";
    
    public static final int SOUND_NO = 0;
    public static final int SOUND_BEEP = 1;
    public static final int SOUND_MELODY = 2;
    
    public static final int DURATION_TWO = 2;
    public static final int DURATION_THIRTY = 30;
    
    private static long vibrationEndTime = 0;
    private static final Object vibrationLock = new Object();
    
    private static Player player = null;
    private static InputStream is = null;
    private static final Object playerLock = new Object();
    private static final PlayerListener playerListener = new PlayerListener() 
    {
        public void playerUpdate(Player player, String event, Object eventData) 
        {
            Notification.playerUpdate(player, event, eventData);
        }
    };
    
    private int id;
    private boolean vibration;
    private boolean backlight;
    private int duration;
    private int sound;
    private int volume;
    
    public Notification(int id)
    {
        this.id = id;
        
        vibration = true;
        backlight = true;
        duration = DURATION_THIRTY;
        sound = SOUND_MELODY;
        volume = 100;
    }

    public Notification(byte[] data) throws IOException
    {
        ByteArrayInputStream bais = new ByteArrayInputStream(data);
        DataInputStream dis = new DataInputStream(bais);
        
        try
        {
            id = dis.readInt();
            vibration = dis.readBoolean();
            backlight = dis.readBoolean();
            duration = dis.readInt();
            sound = dis.readInt();
            volume = dis.readInt();
        }
        finally
        {
            try
            {
                dis.close();
                bais.close();
            }catch(Exception ex){}
        }  
    }
    
    public void start()
    {
        (new Thread(this)).start();
    }
    
    public void run()
    {
        //Вибрация
        vibrate();
        
        //Подсветка 
        backlighting();
        
        //Музыка
        playSound();
    }
    
    private void vibrate() 
    {
        if (vibration && Settings.getSettings().isVibration())
        {
            synchronized(vibrationLock)
            {
                long currentTime = System.currentTimeMillis();
                if (vibrationEndTime < currentTime)
                {
                    Display.getDisplay(IMAPMIDlet.getMidlet()).vibrate(VIBRATION_LENGTH);
                    vibrationEndTime = currentTime + VIBRATION_LENGTH;
                }
            }
        }
    }
    
    private void backlighting()
    {
        if (backlight)
        {
            BacklightHelper.backlight(duration);
        }
    }

    private void playSound()
    {
        int currentVolume = Math.min(volume, Settings.getSettings().getVolume());
        if (sound == SOUND_BEEP)
        {
            try
            {
                Manager.playTone(BEEP_NOTE , BEEP_LENGTH, currentVolume);
            }
            catch(MediaException mex){}
        }
        else if (sound == SOUND_MELODY)
        {
            //Если новый заказ - играем аго музыку
            if (id == NotificationManager.NEW_ORDER)
            {
                cancelMelody();
            }
            
            playMelody(currentVolume);
        }
    }
    
    private void playMelody(int volumeLevel)
    {
        synchronized(playerLock)
        {
            if (player != null)
            {
                return;
            }
            
            try
            {
                is = getClass().getResourceAsStream(getMelodyFileName());
                player = Manager.createPlayer(is, SOUND_TYPE);
                player.addPlayerListener(playerListener);
                player.realize();
                VolumeControl localVolumeControl = (VolumeControl)player.getControl("VolumeControl");
                localVolumeControl.setMute(false);
                localVolumeControl.setLevel(volumeLevel);
                player.start();
            }
            catch(Exception ex)
            {
                try
                {
                    if (player != null)
                    {
                        player.close();
                    }
                }catch (Exception e){}
                if (is != null)
                {
                    try
                    {
                        is.close();
                    }catch(Exception e){}
                }
                player = null;
            }
        }
    }
    
    private void cancelMelody()
    {
        synchronized(playerLock)
        {
            if (player != null)
            {
                try
                {
                    player.stop();
                    Thread.sleep(50);
                }
                catch (Exception e)
                {
                    try
                    {
                      player.close();
                    }catch (Exception ex){}
                    
                    if (is != null)
                    {
                        try
                        {
                            is.close();
                        }catch(Exception ex){}
                    }
                    player = null;
                }
            }
        }
    }
    
    public static void playerUpdate(Player player, String event, Object eventData) 
    {
        synchronized(playerLock)
        {
            if (!player.equals(Notification.player))
            {
                try
                {
                    player.close();
                }catch (Exception e){}
                return;
            }
            if (event.equals(PlayerListener.END_OF_MEDIA) || event.equals(PlayerListener.ERROR) || event.equals(PlayerListener.STOPPED))
            {
                try
                {
                  Notification.player.deallocate();
                }
                catch (Exception e){}
                try
                {
                  Notification.player.close();
                }catch (Exception e){}
                if (is != null)
                {
                    try
                    {
                        is.close();
                    }catch(Exception ex){}
                }
                Notification.player = null;
            }
        }
    }
    
    private String getMelodyFileName()
    {
        switch (id)
        {
            case NotificationManager.NEW_ORDER : return NEW_ORDER_MELODY;
            case NotificationManager.NEW_MESSAGE : return NEW_MESSAGE_MELODY;
            case NotificationManager.ORDER_STATE_CHANGED : return ORDER_STATE_CHANGED_MELODY;
            case NotificationManager.ORDER_CANCELED : return ORDER_CANCELED_MELODY;
            case NotificationManager.CONNECTION_ERROR : return CONNECTION_ERROR_MELODY;
            case NotificationManager.NEW_EFIR_ORDER : return NEW_EFIR_ORDER_MELODY;
            case NotificationManager.FIRST_IN_QUEUE : return FIRST_IN_QUEUE_MELODY;
            default : return "";        
        }
    }
    
    public byte[] toByte()
    {
        ByteArrayOutputStream result = new ByteArrayOutputStream();
        DataOutputStream dos = new DataOutputStream(result);
        
        try
        {
            dos.writeInt(id);
            dos.writeBoolean(vibration);
            dos.writeBoolean(backlight);
            dos.writeInt(duration);
            dos.writeInt(sound);
            dos.writeInt(volume);
            
            return result.toByteArray();
        }
        catch(IOException ioex)
        {
            return (new byte[]{});
        }
        finally
        {
            try
            {
                dos.close();
                result.close();
            }catch(Exception ex){}
        }    
    }

    public void setId(int id) 
    {
        this.id = id;
    }
    
    public int getId() 
    {
        return id;
    }
    
    public boolean isBacklight() 
    {
        return backlight;
    }

    public void setBacklight(boolean backlight) 
    {
        this.backlight = backlight;
    }

    public boolean isVibration() 
    {
        return vibration;
    }

    public void setVibration(boolean vibration) 
    {
        this.vibration = vibration;
    }

    public int getSound() 
    {
        return sound;
    }

    public void setSound(int sound) 
    {
        this.sound = sound;
    }

    public int getVolume() 
    {
        return volume;
    }

    public void setVolume(int volume) 
    {
        this.volume = volume;
    }

    public int getDuration() 
    {
        return duration;
    }

    public void setDuration(int duration) 
    {
        this.duration = duration;
    }
}
